﻿using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web;
using Myotragus.Data.Util;

namespace Myotragus.Store.Models
{
  public static class CultureHelper
  {
    static readonly Regex RexCleanLanguage = new Regex("\\;.*", RegexOptions.Compiled);
    const string StrCultureAtProfile = "Culture";
    const string StrCultureAtSession = "__@@_Culture_@@__";
    public static IEnumerable<string> Cultures
    {
      get
      {
        return CultureProvider.LstCultureNames;
      }
    }

    public static void SetCurrentCulture(string culture)
    {
      var profile = Profile.Current;
      var preferred = GetPreferredCulture(new[] { culture });
      profile[StrCultureAtProfile] = preferred;
      profile.Save();

      HttpContext.Current.Session[StrCultureAtSession] =
        CultureInfo.GetCultureInfo(preferred);
    }
    public static void SetCurrentCulture(CultureInfo culture)
    {
      SetCurrentCulture(culture.Name);
    }

    public static CultureInfo GetCurrentCulture()
    {
      return FromSession() ?? FromProfile() ?? CreateNew() ;
    }

    static CultureInfo FromSession()
    {
      return ExecutionHelper.ControlledExecution(() => 
        (CultureInfo)HttpContext.Current.Session[StrCultureAtSession], null);
    }

    static CultureInfo FromProfile()
    {
      return ExecutionHelper.ControlledExecution(() =>
        CultureInfo.GetCultureInfo((string)Profile.Current[StrCultureAtProfile]), null);
    }

    static CultureInfo CreateNew()
    {
      return CultureInfo.GetCultureInfo(
        GetPreferredCulture(HttpContext.Current.Request.UserLanguages));
    }

    public static CultureInfo GetCulture(string name)
    {
      return CultureInfo.GetCultureInfo(GetPreferredCulture(new [] {name}));
    }

    public static CultureInfo Current
    {
      get
      {
        return GetCurrentCulture();
      }
      set
      {
        SetCurrentCulture(value);
      }
    }

    public static void SetThreadCulture()
    {
      var current = Current;
      if (current.IsNeutralCulture)
        current = CultureInfo.CreateSpecificCulture(current.Name);

      Thread.CurrentThread.CurrentCulture = current;
      Thread.CurrentThread.CurrentUICulture = current;
    }

    private static string CleanCultureName(string culture)
    {
      return RexCleanLanguage.Replace(culture, "");
    }

    private static string GetPreferredCulture(IEnumerable<string> preferred)
    {
      return preferred.FirstOrDefault(p => CultureProvider.LstCultureNames.Contains(p))
             ?? preferred.Where(IsBestMatch).Select(p => BestMatch(p)).First()
             ?? Cultures.First();
    }

    private static string BestMatch(string s)
    {
      try
      {
        var ps = CultureInfo.GetCultureInfo(CleanCultureName(s));
        if (!ps.IsNeutralCulture) ps = ps.Parent;

        var match = from ncul in Cultures
                    let cul = CultureInfo.GetCultureInfo(ncul)
                    where cul == ps || cul.Parent == ps
                    select ncul;

        return match.FirstOrDefault();
      }
      catch
      {
        return null;
      }
    }

    private static bool IsBestMatch(string p)
    {
      return BestMatch(p) != null;
    }
  }
}